package cn.touna.jss.common.util;

import com.alibaba.fastjson.JSON;
import org.dom4j.Attribute;
import org.dom4j.DocumentException;
import org.dom4j.DocumentHelper;
import org.jdom.Document;
import org.jdom.Element;
import org.jdom.JDOMException;
import org.jdom.input.SAXBuilder;
import org.xml.sax.InputSource;

import java.io.IOException;
import java.io.StringReader;
import java.util.*;

public class RaderXml {

    public static Map<String, String> xmlElements(String xmlDoc)
            throws JDOMException, IOException {

        HashMap<String, String> rmap = new HashMap<String, String>();
        // 创建一个新的字符串
        StringReader read = new StringReader(xmlDoc);
        // 创建新的输入源SAX 解析器将使用 InputSource 对象来确定如何读取 XML 输入
        InputSource source = new InputSource(read);
        // 创建一个新的SAXBuilder
        SAXBuilder sb = new SAXBuilder();

        // 通过输入源构造一个Document
        Document doc = sb.build(source);
        // 取的根元素
        Element root = doc.getRootElement();

        // 得到根元素所有子元素的集合
        @SuppressWarnings("unchecked")
        List<Element> node = root.getChildren();

        // 获得XML中的命名空间（XML中未定义可不写）
        // Namespace ns = root.getNamespace();

        for (int i = 0; i < node.size(); i++) {
            Element et = node.get(i);// 循环依次得到子元素
            rmap.put(et.getName(), et.getText());
        }

        return rmap;
    }

    /**
     * 解析嵌套XML,结果转为Map
     *
     * @param xml
     * @return
     * @throws DocumentException
     */
    public static Map<String, Object> xmlToMap(String xml)
            throws DocumentException {
        org.dom4j.Document doc = DocumentHelper.parseText(xml);
        org.dom4j.Element rootElement = doc.getRootElement();
        Map<String, Object> map = new HashMap<String, Object>();
        elementToMap(map, rootElement);
        return map;
    }

    /**
     * 解析嵌套XML,结果转为JSON字符串
     * @param xml
     * @return
     * @throws DocumentException
     */
    public static String xmlToJsonString(String xml) throws DocumentException {
        org.dom4j.Document doc = DocumentHelper.parseText(xml);
        org.dom4j.Element rootElement = doc.getRootElement();
        Map<String, Object> map = new HashMap<String, Object>();
        elementToMap(map, rootElement,false);
        return JSON.toJSONString(map);
    }

    /**
     * 解析嵌套XML,结果转为JSON字符串，节点的属性也会解析到json中<br/>
     * 存在的风险：节点node有attr属性，也有attr子节点，会发生覆盖的现象
     * @param xml
     * @return
     * @throws DocumentException
     */
    public static String xmlToJsonStringWithAttribute(String xml) throws DocumentException {
        org.dom4j.Document doc = DocumentHelper.parseText(xml);
        org.dom4j.Element rootElement = doc.getRootElement();
        Map<String, Object> map = new HashMap<String, Object>();
        elementToMap(map, rootElement,true);
        return JSON.toJSONString(map);
    }

    /**
     * 解析嵌套XML(核心方法,递归调用方式)
     * @param resultMap
     * @param element
     * @param useAttr
     */
    private static void elementToMap(Map<String, Object> resultMap,
                                     org.dom4j.Element element,boolean useAttr) {
        String elementName = element.getName();

        @SuppressWarnings("unchecked")
        List<org.dom4j.Element> subElements = element.elements();
        Map<String,Object> attrMap = null;
        if (subElements.size() == 0) {
            // 没有子节点说明当前节点是叶子节点, 可直接取值
            resultMap.put(elementName, element.getText());
            attrMap = resultMap;
        } else {
            //此处改善，把map抽取出来，最后一起加入resultmap中
            Map<String, Object> map = new HashMap<String, Object>();
            for (org.dom4j.Element subElement : subElements) {
                elementToMap(map, subElement,useAttr);
            }
            //判断原来的resulMap中的值是否已经是一个list。如果是，直接抽取出来进行内容添加，如果不是，则进行数组化
            if (resultMap.containsKey(elementName)) {
                if (resultMap.get(elementName) instanceof List) {
                    List list = (List) resultMap.get(elementName);
                    list.add(map);
                    resultMap.put(elementName, list);
                } else {
                    List list = new ArrayList();
                    list.add(resultMap.get(elementName));
                    list.add(map);
                    resultMap.put(elementName, list);
                }
            } else {
                resultMap.put(elementName, map);
            }
            attrMap = map;
        }

        if(useAttr && attrMap != null){
            List<Attribute> attrs = element.attributes();
            for (Attribute attr : attrs) {
                attrMap.put(attr.getName(),attr.getValue());
            }
        }
    }

    /**
     * 解析嵌套XML(核心方法,递归调用方式)
     * @param resultMap
     * @param element
     */
    private static void elementToMap(Map<String, Object> resultMap,
                                     org.dom4j.Element element) {
        String elementName = element.getName();

        @SuppressWarnings("unchecked")
        List<org.dom4j.Element> subElements = element.elements();

        if (subElements.size() == 0) {
            // 没有子节点说明当前节点是叶子节点, 可直接取值
            resultMap.put(elementName, element.getText());
        } else {
            //此处改善，把map抽取出来，最后一起加入resultmap中
            Map<String, Object> map = new HashMap<String, Object>();
            for (org.dom4j.Element subElement : subElements) {
                elementToMap(map, subElement);
            }
            //判断原来的resulMap中的值是否已经是一个list。如果是，直接抽取出来进行内容添加，如果不是，则进行数组化
            if (resultMap.containsKey(elementName)) {
                if (resultMap.get(elementName) instanceof List) {
                    List list = (List) resultMap.get(elementName);
                    list.add(map);
                    resultMap.put(elementName, list);
                } else {
                    List list = new ArrayList();
                    list.add(resultMap.get(elementName));
                    list.add(map);
                    resultMap.put(elementName, list);
                }
            } else {
                resultMap.put(elementName, map);
            }
        }
    }

    private static boolean hasSame(List<org.dom4j.Element> elements) {
        Set<String> names = new HashSet<String>();
        for (org.dom4j.Element element : elements) {
            names.add(element.getName());
        }
        return names.size() != elements.size();
    }


}
